package fdts.calendar;

/********************************************************
 * FDTS SS 2012. Calendar Layouter and iCalendar Imorter*
 * ******************************************************/

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Insets;
import java.awt.Label;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.KeyEvent;
import java.awt.geom.Rectangle2D;
import java.io.File;
import java.io.IOException;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.xml.parsers.ParserConfigurationException;


import org.xml.sax.SAXException;

import prefuse.Constants;
import prefuse.Display;
import prefuse.Visualization;
import prefuse.action.ActionList;
import prefuse.action.RepaintAction;
import prefuse.action.assignment.ColorAction;
import prefuse.action.assignment.DataColorAction;
import prefuse.action.layout.Layout;
import prefuse.data.Schema;
import prefuse.data.expression.Predicate;
import prefuse.data.io.DataIOException;
import prefuse.data.query.NumberRangeModel;
import prefuse.render.AbstractShapeRenderer;
import prefuse.render.AxisRenderer;
import prefuse.render.DefaultRendererFactory;
import prefuse.util.ColorLib;
import prefuse.util.FontLib;
import prefuse.util.PrefuseLib;
import prefuse.util.ui.UILib;
import prefuse.visual.VisualItem;
import prefuse.visual.expression.InGroupPredicate;
import prefuse.visual.expression.VisiblePredicate;
import prefuse.visual.sort.ItemSorter;

import timeBench.calendar.Granularity;
import timeBench.calendar.JavaDateCalendarManager.Granularities;
import timeBench.data.TemporalDataException;
import timeBench.data.TemporalDataset;

import fdts.calendar.layout.CalendarAxis;
import fdts.calendar.layout.CalendarAxisLabelLayout;
import fdts.calendar.layout.CalendarAxisLayout;
import fdts.calendar.layout.CalendarLabelLayout;
import fdts.calendar.render.CalendarLabelRenderer;
import fdts.calendar.render.CalendarShapeRenderer;
import fdts.data.DataReader;
import fdts.data.io.*;

/**
 * this class implements a standard calendar for the
 * granularities: day, week, month and year.
 * 
 * @author agnieszka wojdecka and andreas hoermann
 *
 */
public class CalendarVisualization implements ActionListener{
	/**
	   stores axes specifications for all granularities
	   String is the name of the granularity
	   ArrayList stores at index 0 the x-axis
	   and at index 1 the y-axis
	*/
	private HashMap<String,ArrayList<CalendarAxis>> axes = null;
	
	/**
	   button for creating a granularity.
	*/
	private JButton createButton = null;
	
	/**
	   drop down list for granularities
	*/
	private JComboBox granularityList = null;
	
	/**
	   data reader
	*/
	private DataReader dataReader = new DataReader();
	
	/**
	 	path to ics data
	*/
	private String path = "";
	
	/**
		panel for GUI elements.
	*/
	private JPanel panel;
	
	/**
		label1 between the navigation arrows.
	*/
	private JLabel tf = new JLabel();
	
	/**
		label2 between the navigation arrows.
	*/
	private JLabel tf2 = new JLabel();
	
	/**
		label3 between the navigation arrows.
	*/
	private JLabel tf3 = new JLabel();
	
	/**
		visualization, stores all actions, renderer and layouter.
	*/
	private final Visualization vis;
	
	/**
		display for vis.
	*/
	private final Display display;
	
	/**
		xAxis in calendar.
	*/
	private CalendarAxisLayout xAxis;
	
	/**
		yAxis in calendar.
	*/
	private CalendarAxisLayout yAxis;
	
	/**
		axis strokes of x axis connected with data.
	*/
	private CalendarAxisLabelLayout xLabels;
	
	/**
		axis strokes and labels of y axis connected with data.
	*/
	private CalendarAxisLabelLayout yLabels;
	
	/**
		color of data labels.
	*/
	private DataColorAction datacolor;
	
	/**
		color of date labels.
	*/
	private DataColorAction datecolor;
	
	/**
		color of boxes.
	*/
	private ColorAction color;
	
	/**
		tabel labels layout.
	*/
	private Layout l1;
	
	/**
		date labels layout.
	*/
	private Layout l2;
	
	/**
		just labels of x-axis.
	*/
	private CalendarAxisLabelLayout xLabels2;
	
	/**
		button to go back in the unity of the view (e.g. in weeks).
	*/
	private JButton buttonBack = new JButton();
	
	/**
		button to go forward in the unity of the view (e.g. in weeks).
	*/
	private JButton buttonForward = new JButton();
	
	/**
		drop down list to choose a granularity
	*/
	private String[] dropdownlist;
	
	/**
		index of position in the dropdownlist.
	*/
	private int index;
	
	/**
		the actual date of the calendar, depends on forward/backward clicks.
	*/
	private int[] actualDate;
	
	/**
	 *  the constructor
	 * @param xmlfolderpath path to folder with xml layout definitions for all granularities
	 * @param pathToIcs path to the ics file (data of calendar).
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 */
	public CalendarVisualization(String xmlfolderpath, String pathToIcs) throws ParserConfigurationException, SAXException, IOException{
		axes = new HashMap<String,ArrayList<CalendarAxis>>();
		vis = new Visualization();
		display = new Display(vis);
		GregorianCalendar cal = new GregorianCalendar();
		cal.setTimeInMillis(System.currentTimeMillis());
		actualDate = new int[3];
		actualDate[0] = cal.get(GregorianCalendar.DAY_OF_MONTH);
		actualDate[1] = cal.get(GregorianCalendar.MONTH)+1;
		actualDate[2] = cal.get(GregorianCalendar.YEAR);
		
		path = pathToIcs;
		
		read(xmlfolderpath);
	}
	
	/**
	    the decorator schema for the data labels
	*/
	private static final Schema DECORATOR_SCHEMA = PrefuseLib.getVisualItemSchema(); 
    static { 
    	DECORATOR_SCHEMA.setDefault(VisualItem.INTERACTIVE, false); 
    	DECORATOR_SCHEMA.setDefault(VisualItem.TEXTCOLOR, ColorLib.gray(128)); 
    	DECORATOR_SCHEMA.setDefault(VisualItem.FONT, FontLib.getFont("Tahoma",14));
    }
    
	/**
	   this method reads out the axes-specifications from a folder
	   and stores it in the member axes.
	   @param xmlfolderpath the folder to the xml-files, that contain the axes-specifications
	*/
	protected void read(String xmlfolderpath) throws ParserConfigurationException, SAXException, IOException{
		// read in the axes definitions
		XMLAxesDefinitionReader reader = new XMLAxesDefinitionReader();
		File directory = new File(xmlfolderpath);
		File files[] = directory.listFiles();
		for (File f : files) {
			axes.put( f.getName().substring(0,f.getName().lastIndexOf(".xml")), reader.read(f));
		}
	}
	
	/**
	   this method run the calendar application.
	*/
	void run(){
		Locale.setDefault(Locale.GERMANY);
		UILib.setPlatformLookAndFeel();
		
		TemporalDataset data = null;
		TemporalDataset date = null;
		try {
			data = dataReader.generateTable(path,"week",axes,System.currentTimeMillis());
			date = dataReader.generateDateTable(axes,"week",tf.getText(),System.currentTimeMillis());
		} catch (ParseException e1) {
			e1.printStackTrace();
		} catch (TemporalDataException e1) {
			e1.printStackTrace();
		} catch (DataIOException e) {
			e.printStackTrace();
		}
		
		try {
			final JComponent display = createVisualization(data,date,"week");
			
			javax.swing.SwingUtilities.invokeLater(new Runnable() {
				
				@Override
				public void run() {
					createAndShowGUI(display);
				}
			});
		} catch (TemporalDataException e) {
			e.printStackTrace();
		}
		
		
	}

	/**
	 * this method builds up the first content of the calendar: builds up vis (layouter, renderer, display).
	 * @param data temporalDataset (timebench) of all calendar data with timestamp (datum) and labels (summary)
	 * @param date temporalDataset (timebench) of all timestamps for every field in the calendar
	 * @param grName String; granularity name
	 * @return JComponent; returns display
	 * @throws TemporalDataException
	 */
	protected JComponent createVisualization(TemporalDataset data,TemporalDataset date, String grName) throws TemporalDataException{
		if(data != null){
			vis.add("data", data.getNodeTable() );
		}	
		if( date != null ){
			vis.add("date", date.getNodeTable() );
		}
		CalendarLabelRenderer nameLabel = new CalendarLabelRenderer("summary");
		nameLabel.setRoundedCorner(8, 8);
		CalendarLabelRenderer nameDate = new CalendarLabelRenderer("datum");
		nameDate.setRoundedCorner(8, 8);
		AbstractShapeRenderer sr = new CalendarShapeRenderer();
		 
		DefaultRendererFactory rf = new DefaultRendererFactory(); 
		rf.setDefaultRenderer(sr);
		rf.add(new InGroupPredicate("ylab"), 
				new AxisRenderer(Constants.FAR_LEFT, Constants.CENTER));
		rf.add(new InGroupPredicate("xlab_labels"), 
				new AxisRenderer(Constants.CENTER, Constants.FAR_TOP));
		rf.add(new InGroupPredicate("xlab_axis"), 
				new AxisRenderer(Constants.CENTER, Constants.FAR_TOP));
		rf.add(new InGroupPredicate("TABEL_LABELS"), 
				nameLabel);
		rf.add(new InGroupPredicate("DATE_LABELS"), 
				nameDate);
		vis.setRendererFactory(rf);
		 
		if(data != null){
			vis.addDecorators("TABEL_LABELS", "data", DECORATOR_SCHEMA);
		}
		if(date != null){
			vis.addDecorators("DATE_LABELS", "date", DECORATOR_SCHEMA);
		}
		Granularity xGranularity = axes.get(grName).get(0).granularity;
		Granularity yGranularity = axes.get(grName).get(1).granularity;
		
		xAxis = getAxis(xGranularity,Constants.X_AXIS,axes.get(grName).get(0).specification.perpage,VisiblePredicate.TRUE);
		yAxis = getAxis(yGranularity,Constants.Y_AXIS,axes.get(grName).get(1).specification.perpage,VisiblePredicate.TRUE);
		
		if(xAxis != null && yAxis != null){
			final Rectangle2D boundsData = new Rectangle2D.Double();
			final Rectangle2D boundsLabelsX = new Rectangle2D.Double();
			final Rectangle2D boundsLabelsY = new Rectangle2D.Double();
			
			xAxis.setLayoutBounds(boundsData);
			yAxis.setLayoutBounds(boundsData);
			
			xLabels = new CalendarAxisLabelLayout("xlab_axis", xAxis, boundsLabelsX);
			xLabels2 = new CalendarAxisLabelLayout("xlab_labels", xAxis, boundsLabelsX);
			yLabels = new CalendarAxisLabelLayout("ylab", yAxis, boundsLabelsY);
			xLabels.setGran(grName);
            yLabels.setGran(grName);
            xLabels.setDate(actualDate[2], actualDate[1], actualDate[0]);
            yLabels.setDate(actualDate[2], actualDate[1], actualDate[0]);
            xLabels2.setGran(grName);
            xLabels2.setDate(actualDate[2], actualDate[1], actualDate[0]);

            NumberFormat nf = NumberFormat.getNumberInstance();
	        nf.setMaximumFractionDigits(0);
	        yLabels.setNumberFormat(nf);
			yLabels.setAscending(false);
			
			ActionList draw = new ActionList();
			
			ColorAction edgeStrokes;
			
			if(data != null && date != null){
				color = new ColorAction("data", VisualItem.FILLCOLOR , ColorLib.rgb(100, 100, 255));
				edgeStrokes = new ColorAction("data", VisualItem.STROKECOLOR,ColorLib.rgb(0, 0, 0));
				draw.add(color);
				draw.add(edgeStrokes);
			}
			
			draw.add(xAxis);
			draw.add(yAxis);
			draw.add(xLabels);
			draw.add(xLabels2);
			draw.add(yLabels);
			
			if(data != null && date != null){
				int [] palette1 = new int[]{ColorLib.rgb(150, 150, 150)};
				int [] palette2 = new int[]{ColorLib.rgb(255, 255, 255)};
				datecolor = new DataColorAction("DATE_LABELS","datum",Constants.NOMINAL, VisualItem.TEXTCOLOR, palette1);
				datacolor = new DataColorAction("TABEL_LABELS","summary",Constants.NOMINAL, VisualItem.TEXTCOLOR, palette2);
				ColorAction text2 = new ColorAction("xlab_axis",VisualItem.TEXTCOLOR,0); // no color
				ColorAction strokecol = new ColorAction("xlab_labels",VisualItem.STROKECOLOR,0); // no color
				
				l1 = new CalendarLabelLayout("TABEL_LABELS","xlab_labels","ylab","week");
				l2 = new CalendarLabelLayout("DATE_LABELS","xlab_labels","ylab","week");
		        boundsLabelsX.getBounds().width = boundsLabelsX.getBounds().width - 50;
		        l1.setLayoutBounds(boundsLabelsX);
		        l2.setLayoutBounds(boundsLabelsX);
		        
				draw.add(l1);
				draw.add(l2);
				draw.add(datacolor);
				draw.add(datecolor);
				draw.add(text2);
				draw.add(strokecol);
			}
			
			draw.add(new RepaintAction());
			vis.putAction("draw", draw);
			
			display.setHighQuality(true);
			display.setSize(700,450);
			display.setAutoscrolls(true);
			display.setBorder(BorderFactory.createTitledBorder("Calendar week view"));
			
			// data items will be displayed in front of the grid lines
			display.setItemSorter(new ItemSorter() {
				public int score(VisualItem item){
					int score = super.score(item);
					if(item.isInGroup("data")){
						score++;
					}
					return score;
				}
			});
			
			display.addComponentListener(new ComponentAdapter() {
				public void componentResized(ComponentEvent e) {
					updateBounds(display, boundsData, boundsLabelsX, boundsLabelsY);
					vis.run("draw");
				}
			});
			
			updateBounds(display, boundsData, boundsLabelsX, boundsLabelsY);
			vis.run("draw");
		}// xAxis != null && yAxis != null
		return display;
	}
	
	/**
	 * this method updates vis. all labels and boxes are rendered anew 
	 * accordingly to the new data and date entries.
	 * 
	 * @param data temporalDataset (timebench) of all calendar data with timestamp (datum) and labels (summary)
	 * @param date temporalDataset (timebench) of all timestamps for every field in the calendar
	 * @param grName String; granularity name
	 * @throws TemporalDataException
	 */
	protected void update(TemporalDataset data, TemporalDataset date, String grName) throws TemporalDataException{
		if(data != null){
			vis.removeGroup("data");
			vis.add("data", data.getNodeTable() );
			vis.removeGroup("TABEL_LABELS");
			vis.addDecorators("TABEL_LABELS", "data", DECORATOR_SCHEMA);
		}
		if(date != null){
			vis.removeGroup("date");
			vis.add("date", date.getNodeTable() );
			vis.removeGroup("DATE_LABELS");
			vis.addDecorators("DATE_LABELS", "date", DECORATOR_SCHEMA);
		}
		
		Granularity xGranularity = axes.get(grName).get(0).granularity;
		Granularity yGranularity = axes.get(grName).get(1).granularity;
		
		xAxis = getAxis(xGranularity,Constants.X_AXIS,axes.get(grName).get(0).specification.perpage,VisiblePredicate.TRUE);
		yAxis = getAxis(yGranularity,Constants.Y_AXIS,axes.get(grName).get(1).specification.perpage,VisiblePredicate.TRUE);
		
		if(xAxis != null && yAxis != null){
			final Rectangle2D boundsData = new Rectangle2D.Double();
			final Rectangle2D boundsLabelsX = new Rectangle2D.Double();
			final Rectangle2D boundsLabelsY = new Rectangle2D.Double();
				
			xAxis.setLayoutBounds(boundsData);
			yAxis.setLayoutBounds(boundsData);
			
			vis.removeGroup("xlab_axis");
			vis.removeGroup("xlab_labels");
			vis.removeGroup("ylab");
			
			xLabels.switchAxis(xAxis);
			xLabels2.switchAxis(xAxis);
			yLabels.switchAxis(yAxis);
			
            xLabels.setDate(actualDate[2], actualDate[1], actualDate[0]);
            xLabels2.setDate(actualDate[2], actualDate[1], actualDate[0]);
            yLabels.setDate(actualDate[2], actualDate[1], actualDate[0]);
            
			xLabels.setGran(grName);
			xLabels2.setGran(grName);
            yLabels.setGran(grName);
            
			NumberFormat nf = NumberFormat.getNumberInstance();
	        nf.setMaximumFractionDigits(0);
	        yLabels.setNumberFormat(nf);
			yLabels.setAscending(false);
			
			ActionList draw = new ActionList();
			ColorAction edgeStrokes;
			
			if(data != null && date != null){
				color = new ColorAction("data", VisualItem.FILLCOLOR , ColorLib.rgb(100, 100, 255));
				edgeStrokes = new ColorAction("data", VisualItem.STROKECOLOR,ColorLib.rgb(0, 0, 0));
				draw.add(color);
				draw.add(edgeStrokes);
			}
			
			draw.add(xAxis);
			draw.add(yAxis);
			draw.add(xLabels2);
			draw.add(xLabels);
			draw.add(yLabels);
			
			if(data != null && date != null){
				int [] palette1 = new int[]{ColorLib.rgb(150, 225, 255)};
				int [] palette2 = new int[]{ColorLib.rgb(255, 255, 255)};
				datacolor = new DataColorAction("TABEL_LABELS","summary",Constants.NOMINAL, VisualItem.TEXTCOLOR, palette2);
				datecolor = new DataColorAction("DATE_LABELS","datum",Constants.NOMINAL, VisualItem.TEXTCOLOR, palette1);
				ColorAction text2 = new ColorAction("xlab_axis",VisualItem.TEXTCOLOR,0); // no color
				ColorAction strokecol = new ColorAction("xlab_labels",VisualItem.STROKECOLOR,0); // no color
				
				l1 = new CalendarLabelLayout("TABEL_LABELS","xlab_labels","ylab",(String)granularityList.getSelectedItem());
				l2 = new CalendarLabelLayout("DATE_LABELS","xlab_labels","ylab",(String)granularityList.getSelectedItem());
		        boundsLabelsX.getBounds().width = boundsLabelsX.getBounds().width - 50;
		        l1.setLayoutBounds(boundsLabelsX);
		        l2.setLayoutBounds(boundsLabelsX);
				
		        draw.add(l1);
		        draw.add(l2);
				draw.add(datacolor);
				draw.add(datecolor);
				draw.add(text2);
				draw.add(strokecol);
			}
		
			draw.add(new RepaintAction());
			vis.removeAction("draw");
			vis.putAction("draw", draw);
			
			display.setBorder(BorderFactory.createTitledBorder("Calendar "+ granularityList.getSelectedItem() +" view"));
			
			// data items will be displayed in front of the grid lines
			display.setItemSorter(new ItemSorter() {
				public int score(VisualItem item){
					int score = super.score(item);
					if(item.isInGroup("data")){
						score++;
					}
					return score;
				}
			});
			
			display.addComponentListener(new ComponentAdapter() {
				public void componentResized(ComponentEvent e) {
					updateBounds(display, boundsData, boundsLabelsX, boundsLabelsY);
					vis.run("draw");
				}
			});

			updateBounds(display, boundsData, boundsLabelsX, boundsLabelsY);
			vis.run("draw"); 
		}// xAxis != null && yAxis != null
		
	}
	
	/**
	 * updates bounds. is necessary for scaling the calendar window.
	 * @param display the display of the application
	 * @param boundsData the bounds of the data
	 * @param boundsLabelsX	the bounds of the labels accordingly to the x axis
	 * @param boundsLabelsY the bounds of the labels accordingly to the y axis
	 */
	private static void updateBounds(Display display, Rectangle2D boundsData,
			Rectangle2D boundsLabelsX, Rectangle2D boundsLabelsY) {
 
		int paddingLeft = 60;
		int paddingTop = 30;
		int paddingRight = 60;
		int paddingBottom = 30;
 
		int axisWidth = 20;
		int axisHeight = 10;
 
		Insets i = display.getInsets();
 
		int left = i.left + paddingLeft;
		int top = i.top + paddingTop;
		int innerWidth = display.getWidth() - i.left - i.right - paddingLeft
				- paddingRight;
		int innerHeight = display.getHeight() - i.top - i.bottom - paddingTop
				- paddingBottom;
 
		boundsData.setRect(left, top, innerWidth - axisWidth,
				innerHeight - axisHeight);
	
		boundsLabelsX.setRect(left, top,
				innerWidth - axisWidth, innerHeight);
		boundsLabelsY.setRect(left, top, innerWidth, innerHeight
				- axisHeight);
	}
	
	/**
	 * this method gets a new CalendarAxisLayout object accordingly to the param of the method.
	 * @param granularity the granularity
	 * @param type the axis type, Constants.X_AXIS or Constants.Y_AXIS
	 * @param perpage e.g. if day is the granularity, this value specifies how many days are
	 * displayed at a page. is used to set the range of the axis.
	 * @param visibility Predicate e.g. VisiblePredicate.TRUE
	 * @return returns a axis layout specified for this application, with the following constants: 
	 * data, TABEL_LABELS, DATE_LABELS, xstart/ystart, xend/yend and the name of the granularity e.g. hour.
	 * @throws TemporalDataException
	 */
	CalendarAxisLayout getAxis(Granularity granularity, int type, int perpage, Predicate visibility) throws TemporalDataException{
		CalendarAxisLayout axis = null;

		switch(Granularities.fromInt(granularity.getIdentifier())){
			case Hour:{	
				if(type == Constants.X_AXIS)
					axis = new CalendarAxisLayout("data", "TABEL_LABELS", "DATE_LABELS", "xstart", "xend", "hour", type,visibility);
				else
					axis = new CalendarAxisLayout("data", "TABEL_LABELS", "DATE_LABELS", "ystart", "yend",  "hour", type, visibility);
				
				axis.setRangeModel(new NumberRangeModel(0, perpage, 0, perpage));
				
				break;
			}
			case Day:{
				if(type == Constants.X_AXIS)
					axis = new CalendarAxisLayout("data", "TABEL_LABELS", "DATE_LABELS", "xstart", "xend", "day", type, visibility);
				else
					axis = new CalendarAxisLayout("data", "TABEL_LABELS", "DATE_LABELS", "ystart", "yend",  "day", type, visibility);
				
				axis.setRangeModel(new NumberRangeModel(0, perpage, 0, perpage));
				
				break;
			}
			case Week:{
				if(type == Constants.X_AXIS)
					axis = new CalendarAxisLayout("data", "TABEL_LABELS", "DATE_LABELS", "xstart", "xend", "week", type, visibility);
				else
					axis = new CalendarAxisLayout("data", "TABEL_LABELS", "DATE_LABELS", "ystart", "yend",  "week", type, visibility);
				
				axis.setRangeModel(new NumberRangeModel(0, perpage, 0, perpage));
				
				break;
			}
			case Month:{
				if(type == Constants.X_AXIS)
					axis = new CalendarAxisLayout("data", "TABEL_LABELS", "DATE_LABELS", "xstart", "xend", "month", type, visibility);
				else
					axis = new CalendarAxisLayout("data", "TABEL_LABELS", "DATE_LABELS", "ystart", "yend",  "month", type, visibility);
				
				axis.setRangeModel(new NumberRangeModel(0, perpage, 0, perpage));
				
				break;
			}
			default: System.out.println( "Granularity for Axis not supported at the moment!" );
				break;
		}
		
		return axis;
	}
	
	/**
	   this method creates and shows the GUI
	   @param display the JComponent that was created by createVisualization.
	*/
	public void createAndShowGUI(JComponent display){
		//JFrame frame = new JFrame();
		
        JFrame frame = new JFrame("BorderLayoutDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setTitle("f d t s C a l e n d a r");
        
        Container pane = frame.getContentPane();
        
        if (!(pane.getLayout() instanceof BorderLayout)) {
            pane.add(new JLabel("Container doesn't use BorderLayout!"));
            return;
        }
        
        //OBEN
        
	        //Panel
	        panel = new JPanel();
	        panel.setBackground(Color.white);
			
			//Buttons
	        GregorianCalendar cal = new GregorianCalendar();
			
			tf.setText(""+cal.get(GregorianCalendar.WEEK_OF_YEAR));
	        
	        buttonBack.setLabel("<");
	        buttonBack.addActionListener(this);
	          
	        buttonForward.setLabel(">");
	        buttonForward.addActionListener(this);
	        
	        dropdownlist = new String[axes.size()];
			index = 0;
			int memIndex = 0;
			Iterator<String> iter = axes.keySet().iterator();
			while(iter.hasNext()){
				dropdownlist[index] = iter.next();
				if(dropdownlist[index].equals("week"))
					memIndex = index;
				index++;
			}
	        
	      //Create the combo box, select item at index 4.
			//Indices start at 0, so 4 specifies the pig.
			granularityList = new JComboBox(dropdownlist);
			granularityList.setSelectedIndex(memIndex);
			granularityList.addActionListener(this);
	        
	        panel.add(buttonBack);
	        String str = (String)granularityList.getSelectedItem();
	        
		    //panel.add(new JLabel(" KW "));
		    
		    tf2.setText("Week");
		    tf3.setText(", "+actualDate[2]);
		    panel.add(tf2);	
		    panel.add(tf);
		    panel.add(tf3);

	        panel.add(buttonForward);
			
			panel.add(new Label("                       Choose:"));
			
									
			panel.add(granularityList);
			panel.add(new Label("                       "));
			
			//Add Setting Button
			ImageIcon buttonIcon = new ImageIcon("settings.png");
			//createButton = new JButton( "New" );
			createButton = new JButton();
			createButton.setIcon(buttonIcon);
			createButton.addActionListener( this );
			createButton.setMnemonic( KeyEvent.VK_N );
			
			panel.add(createButton);
		
        pane.add(panel, BorderLayout.PAGE_START);
        
        //ZENTRUM
        pane.add(display, BorderLayout.CENTER);
        
		frame.pack();
		frame.setVisible(true);
	}

	/**
	 * is  only used to read out the current week
	 * @return
	 */
	private int getTf(){
		return Integer.parseInt(tf.getText());
	}
	
	/**
	 * Handling the user-interaction with the buttons and drop-down list.
	 */
	@Override
	public void actionPerformed(ActionEvent e) {
		
		String str = (String)granularityList.getSelectedItem();
		TemporalDataset data = null;
		TemporalDataset date = null;
		if(e.getSource() == granularityList){	
			// just update below
		}else if(e.getSource() == buttonBack){
			GregorianCalendar cal = new GregorianCalendar();
			GregorianCalendar calendar = new GregorianCalendar(cal.get(GregorianCalendar.YEAR-1), 1, 1);
    		int max = calendar.getActualMaximum(Calendar.WEEK_OF_YEAR);
			int n; 
			
			if(str.equals("week")){
				n = getTf();
				if(n==1) n=max+1;
	            tf.setText("" + (n - 1));
	            actualDate[0] -= 7;
	            xLabels.setDate(actualDate[2], actualDate[1], actualDate[0]);
	            yLabels.setDate(actualDate[2], actualDate[1], actualDate[0]);
		    }
		    	
			if(str.equals("day")){
				actualDate[0]--;
				xLabels.setDate(actualDate[2], actualDate[1], actualDate[0]);
			}
			if(str.equals("month")){
				actualDate[1]--;
			}
			if(str.equals("year")){
				actualDate[2]--;
			}
		}else if(e.getSource() == buttonForward){
			GregorianCalendar cal = new GregorianCalendar();
			GregorianCalendar calendar = new GregorianCalendar(cal.get(GregorianCalendar.YEAR), 1, 1);
    		int max = calendar.getActualMaximum(Calendar.WEEK_OF_YEAR);
			int n;
			            
            if(str.equals("week")){
				n = getTf();
				if(n==max) n=0;
	            tf.setText("" + (n + 1));
	            actualDate[0] += 7;
	            xLabels.setDate(actualDate[2], actualDate[1], actualDate[0]);
	            yLabels.setDate(actualDate[2], actualDate[1], actualDate[0]);
		    }
		    	
			if(str.equals("day")){
				actualDate[0]++;
				xLabels.setDate(actualDate[2], actualDate[1], actualDate[0]);
			}
			if(str.equals("month")){
				actualDate[1]++;
			}
			if(str.equals("year")){
				actualDate[2]++;
			}
		}else
			;
		
		// update calendar
		try {
			GregorianCalendar cal = new GregorianCalendar(actualDate[2], actualDate[1]-1, actualDate[0]);
			
			data = dataReader.generateTable(path,str,axes,cal.getTimeInMillis());
			date = dataReader.generateDateTable(axes,(String)granularityList.getSelectedItem(),tf.getText(),cal.getTimeInMillis());
			
			panel.remove(tf3);
			
			//Labels
			if(str.equals("week")){
				panel.remove(tf);
	            tf2.setText("Week " + cal.get(GregorianCalendar.WEEK_OF_YEAR) + " , "+ cal.get(GregorianCalendar.YEAR));
			}
			if(str.equals("day")){
				panel.remove(tf);
				String name = "";
				switch(cal.get(GregorianCalendar.DAY_OF_WEEK)){
				case 1: name = "SU"; break;
				case 2: name = "MO"; break;
				case 3: name = "TU"; break;
				case 4: name = "WE"; break;
				case 5: name = "TH"; break;
				case 6: name = "FR"; break;
				case 7: name = "SA"; break;
				}
	            tf2.setText(name + " " + cal.get(GregorianCalendar.DAY_OF_MONTH) + "." + (cal.get(GregorianCalendar.MONTH)+1) + "." + cal.get(GregorianCalendar.YEAR));
			}
			if(str.equals("month")){
				GregorianCalendar cal1 = new GregorianCalendar(actualDate[2], actualDate[1]-1, 1);
				if(cal.get(GregorianCalendar.MONTH) != cal1.get(GregorianCalendar.MONTH)){
					int day = actualDate[0];
					if( cal.after(cal1) ){
						while(cal.get(GregorianCalendar.MONTH) != cal1.get(GregorianCalendar.MONTH)){
							day--;
							cal.set(actualDate[2],actualDate[1]-1, day);
						}
					}else{
						while(cal.get(GregorianCalendar.MONTH) != cal1.get(GregorianCalendar.MONTH)){
							day++;
							cal.set(actualDate[2],actualDate[1]-1, day);
						}
					}
				}
				panel.remove(tf);
				String name = "";
				switch(cal.get(GregorianCalendar.MONTH)+1){
				case 1: name = "Jan"; break;
				case 2: name = "Feb"; break;
				case 3: name = "Mar"; break;
				case 4: name = "Apr"; break;
				case 5: name = "May"; break;
				case 6: name = "Jun"; break;
				case 7: name = "Jul"; break;
				case 8: name = "Aug"; break;
				case 9: name = "Sep"; break;
				case 10: name = "Oct"; break;
				case 11: name = "Nov"; break;
				case 12: name = "Dec"; break;
				}
	            tf2.setText(name + ", " + cal.get(GregorianCalendar.YEAR)); 
			}
			if(str.equals("year")){
				panel.remove(tf);
	            tf2.setText("Year " + cal.get(GregorianCalendar.YEAR));
			}
			
			update(data,date,str);
		} catch (ParseException e1) {
			e1.printStackTrace();
		} catch (TemporalDataException e1) {
			e1.printStackTrace();
		} catch (DataIOException e1) {
			e1.printStackTrace();
		}
	}
	
	/**
	   starting point of application
	   @param args path to axes definitions and path to ics-file
	*/
	public static void main(String[] args){
		if(args.length < 2){
			System.out.println( "usage: <path to axes definitions, path to ics-file>" );
			return;
		}
		
		try {
			CalendarVisualization vis = new CalendarVisualization(args[0],args[1]);
			vis.run();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch(Exception e){
			e.printStackTrace();
		}
	}
}